<template>
	<div v-if="searchItems.length" class="card table-search">
		<el-form
			ref="searchFormRef"
			:model="value"
			:label-width="searchLabelWidth"
			class="table-search-form"
			inline
			@submit.prevent
			@keyup.enter="search"
		>
			<div
				:style="{
					maxHeight: state.collapse ? state.formCollapseHeight + 'px' : '500px',
					overflow: 'hidden',
					transition: 'max-height 0.3s'
				}"
			>
				<div ref="formContentRef" class="formContent">
					<el-form-item class="operation" label-width="0px">
						<ProSearchOperation
							:show-collapse="state.showCollapse"
							v-model:collapse="state.collapse"
							@search="search"
							@reset="reset"
						/>
					</el-form-item>
					<el-form-item v-for="item in searchItems" :key="item.prop" :label="item.label" :prop="item.prop">
						<div :style="{ width: item.searchWidth || componentInfo(item).width, height: '38px' }">
							<slot :name="'search_' + item.prop" v-bind="{ searchParam: value, prop: item.prop, data: item }">
								<!-- <el-input v-model.trim="value[item.prop!]" clearable /> -->
								<component :is="componentIs(item)" v-model="value[item.prop!]" v-bind="componentProps(item)"></component>
							</slot>
						</div>
					</el-form-item>
				</div>
			</div>
		</el-form>
	</div>
</template>

<script setup lang="ts" name="ProSearch">
import { ref, reactive, computed, watch, onMounted, onUnmounted } from 'vue'
// 导入兼容模块
import ResizeObserver from 'resize-observer-polyfill'
import ProSearchOperation from './components/ProSearchOperation/index.vue'
import { ColumnProps } from '@/components/ProTable/interface'

// 默认值
const props = withDefaults(
	defineProps<{
		searchLabelWidth?: string // 搜索 label 宽度
		// searchItems: { [key: string]: any }[] // 搜索字段
		searchItems: Partial<ColumnProps>[] // 搜索字段
		modelValue?: { [key: string]: any } // searchParam
		reset?: Function // 重置方法
	}>(),
	{
		searchLabelWidth: '100px',
		modelValue: () => ({})
	}
)
const emits = defineEmits(['update:modelValue', 'search', 'reset'])
// vmodel
const value = computed({
	get() {
		return props.modelValue
	},
	set(newVal: any) {
		emits('update:modelValue', newVal)
	}
})

let state = reactive({
	// 是否折叠
	collapse: true,
	showCollapse: true,
	// form 折叠高度
	formCollapseHeight: 56,
	// form 高度
	formHeight: 0
})

/* 监听 resize 变化 */
const formContentRef = ref()
const handleResize = () => {
	state.formHeight = formContentRef.value.getBoundingClientRect().height
	state.showCollapse = state.formHeight > state.formCollapseHeight
}
const resizeObserver = new ResizeObserver(handleResize)
onMounted(() => {
	if (props.searchItems.length) {
		handleResize()
		resizeObserver.observe(formContentRef.value)
	}
})
onUnmounted(() => {
	resizeObserver.disconnect()
})

watch(
	props.searchItems,
	() => {
		const searchParam: { [key: string]: any } = {}
		for (let index = 0; index < props.searchItems.length; index++) {
			const e = props.searchItems[index]
			searchParam[e.prop!] = e.searchInitParam ?? value.value[e.prop!] ?? null
		}

		Object.assign(value.value, searchParam)
	},
	{ immediate: true }
)

const searchFormRef = ref()
/** 查询列表 */
const search = () => {
	emits('search', value.value)
}
/** 重置 */
const reset = () => {
	if (props.reset) {
		props.reset(searchFormRef.value)
	} else {
		searchFormRef.value.resetFields()
		search()
	}
	emits('reset', value.value)
}
/* 组件映射 */
const compMap: { [key: string]: any } = {
	text: {
		componentName: 'el-input',
		width: '210px',
		props: {
			placeholder: '请输入',
			clearable: true
		}
	},
	select: {
		componentName: 'DictSelect',
		width: '210px',
		props: {
			placeholder: '请选择',
			clearable: true
		}
	},
	multipleSelect: {
		componentName: 'DictSelect',
		width: '210px',
		props: {
			placeholder: '请选择',
			clearable: true,
			multiple: true
		}
	},
	treeSelect: {
		componentName: 'el-tree-select',
		width: '210px',
		props: {
			placeholder: '请选择',
			clearable: true
		}
	},
	multipleTreeSelect: {
		componentName: 'el-tree-select',
		width: '210px',
		props: {
			placeholder: '请选择',
			clearable: true,
			multiple: true
		}
	},
	date: {
		componentName: 'el-date-picker',
		width: '210px',
		props: {
			valueFormat: 'YYYY-MM-DD',
			type: 'date',
			placeholder: '请选择日期',
			clearable: true
		}
	},
	timerange: {
		componentName: 'el-time-picker',
		width: '520px',
		props: {
			isRange: true,
			valueFormat: 'HH:mm:ss',
			rangeSeparator: '至',
			startPlaceholder: '开始时间',
			endPlaceholder: '结束时间',
			clearable: true
		}
	},
	daterange: {
		componentName: 'el-date-picker',
		width: '520px',
		props: {
			type: 'daterange',
			valueFormat: 'YYYY-MM-DD',
			rangeSeparator: '至',
			startPlaceholder: '开始时间',
			endPlaceholder: '结束时间',
			clearable: true
		}
	},
	datetimerange: {
		componentName: 'el-date-picker',
		width: '520px',
		props: {
			type: 'datetimerange',
			valueFormat: 'YYYY-MM-DD HH:mm:ss',
			rangeSeparator: '至',
			startPlaceholder: '开始时间',
			endPlaceholder: '结束时间',
			clearable: true
		}
	}
}
/* 组件名 */
const componentInfo = (item: Partial<ColumnProps>): any => {
	if (!item.searchType) {
		// 没有就默认是 text
		return compMap.text
	}
	return compMap[item.searchType]
}
const componentProps = (item: Partial<ColumnProps>): any => {
	const props = componentInfo(item).props
	return {
		...props,
		options: item.enum,
		...item.searchProps
	}
}
const componentIs = (item: Partial<ColumnProps>): string => {
	return componentInfo(item).componentName
}
</script>
<style scoped lang="scss">
.table-search {
	padding: 22px 22px 0;
	background-color: var(--el-fill-color-blank);
	border: 1px solid var(--el-border-color-light);
	.el-form-item {
		margin-right: 5px;
		.el-input,
		.el-select,
		.el-date-editor--timerange {
			width: 100%;
		}
		.el-date-editor--datetimerange,
		.el-date-editor--daterange {
			width: 380px;
		}

		// 去除时间选择器上下 padding
		.el-range-editor.el-input__wrapper {
			padding: 0 10px;
		}

		// el-select 为多选时不换行显示
		.el-select__tags {
			overflow: hidden;
			white-space: nowrap;
		}
	}

	// .el-form-item {
	//   display: inherit;
	// }
	.operation {
		float: right;
		:deep(.operation-container) {
			width: 215px;
		}
	}
}
</style>
